/*
 *  Copyright (C) 1993  Robert Davis
 *
 *  This program is free software; you can redistribute it and/or
 *  modify it under the terms of Version 2, or any later version, of 
 *  the GNU General Public License as published by the Free Software 
 *  Foundation.
 */


static char RCSId[]="$Id: StatusTics.m,v 1.4 1993/05/04 16:22:53 davis Exp $";

#import <stdlib.h>

#import "DoubleValueSortedList.h"
#import "StatusTics.h"
#import "TicObject.h"

/* structs from plot.h */

struct ticdef {
    int type;				/* one of three constants	*/
    union {
	struct {			/* for TIC_SERIES		*/
	    double start, incr;
	    double end;
	} series;
	struct ticmark *user;		/* for TIC_USER			*/
    } def;
};

struct ticmark {
    double position;			/* where on axis is this	*/
    char *label;			/* optional string label	*/
    struct ticmark *next;		/* linked list			*/
};



extern int tic_in;			/* s_tics_in			*/
extern int xtics, ytics, ztics;		/* s_ticsCoord[]		*/
extern struct ticdef xticdef;		/* s_ticdefCoord[]		*/
extern struct ticdef yticdef;
extern struct ticdef zticdef;

/*
 *  Frees the list of ticmarks whose head is pointed to by t and sets
 *  t to NULL.
 */
static void _freeLinkedList(struct ticmark **t)
{
    struct ticmark *cur;

    while (*t) {
	cur = *t;
	*t = (*t)->next;
	free (cur);
    }

    *t = NULL;
    return;
}



@implementation Status (Tics)

- initTics
{
    int counter;

    for (counter = 0 ; counter < 3 ; counter++)
	ticDefs[counter] = nil;

    return self;
}


- freeTics
{
    int	counter;

    for (counter = 0 ; counter < 3 ; counter++)
	if (ticDefs[counter])
	    [[ticDefs[counter] freeObjects] free];

    return self;
}


- resetCurrentTics
{
    int counter;

    for (counter = 0 ; counter < 3 ; counter++)  {
	s_ticsCoord[counter] = 1;
	s_ticTypeCoord[counter] = TIC_COMPUTED;
	s_ticSeriesCoord[counter].start = -10.0;
	s_ticSeriesCoord[counter].incr = 5.0;
	s_ticSeriesCoord[counter].end = 10.0;
	if (ticDefs[counter])
	    [ticDefs[counter] freeObjects];
	else
	    ticDefs[counter] = [[DoubleValueSortedList allocFromZone:zone]
						       init];
    }

    s_tics_in = YES;

    return self;
}


- applyCurrentTics
{
    int			count;
    struct ticmark	*new;
    id			tic;
    struct ticdef	*ticd[3] = {&xticdef, &yticdef, &zticdef};
    int			i;

    tic_in = s_tics_in;
    xtics = s_ticsCoord[X_TAG];
    ytics = s_ticsCoord[Y_TAG];
    ztics = s_ticsCoord[Z_TAG];

    for (i = 0; i <= 2; i++) {

	switch (s_ticTypeCoord[i]) {
	case TIC_SERIES:
	    ticd[i]->def.series.start = s_ticSeriesCoord[i].start;
	    ticd[i]->def.series.incr = s_ticSeriesCoord[i].incr;
	    ticd[i]->def.series.end = s_ticSeriesCoord[i].end;
	    break;
	case TIC_USER:
	    if (ticd[i]->type == TIC_USER)
		_freeLinkedList (&(ticd[i]->def.user));
	    else
		ticd[i]->def.user = NULL;
	    if ((count = [ticDefs[i] count] - 1) >= 0) {
		new = ticd[i]->def.user = malloc (sizeof (struct ticmark));
		while (count >= 0) {
		    new->position = [tic = [ticDefs[i] objectAt:count]
				     doubleValue];
		    new->label = (char *) [tic stringValue];
		    if (count--) {
			new->next = malloc (sizeof (struct ticmark));
			new = new->next;
		    } else
			new->next = NULL;
		}
		break;
	    }
	}
	ticd[i]->type = s_ticTypeCoord[i];

    }

    return self;
}


- grabCurrentTics
{
    int			count, t;
    struct ticmark	*cur;
    id			tic;
    struct ticdef	*ticd[3] = {&xticdef, &yticdef, &zticdef};
    int			i;

    s_tics_in = tic_in;
    s_ticsCoord[X_TAG] = xtics;
    s_ticsCoord[Y_TAG] = ytics;
    s_ticsCoord[Z_TAG] = ztics;

    for (i = 0; i <= 2; i++) {

	switch (s_ticTypeCoord[i] = ticd[i]->type) {
	case TIC_SERIES:
	    s_ticSeriesCoord[i].start = ticd[i]->def.series.start;
	    s_ticSeriesCoord[i].incr = ticd[i]->def.series.incr;
	    s_ticSeriesCoord[i].end = ticd[i]->def.series.end;
	    break;
	case TIC_USER:
	    count = [ticDefs[i] count] - 1;
	    t = 0;
	    for (cur = ticd[i]->def.user ; cur != NULL ; cur = cur->next) {
		if (t <= count) {
		    [tic = [ticDefs[i] objectAt:t]
					 setDoubleValue:cur->position];
		    [tic setStringValue:cur->label];
		} else {
		    TicObject *tobj = [[TicObject allocFromZone:zone]
						 initFromString:cur->label
						    doubleValue:cur->position];
		    if ([ticDefs[i] addObjectIfDoubleAbsent:tobj]
			== NX_NOT_IN_LIST)
			[tobj free];

		}
		t++;
	    }
	    break;
	}

    }

    return self;
}


- setTicsIn:(BOOL) cond
{
    if (s_tics_in != cond) {
	s_tics_in = cond;
	[self reportSettingsChange:self];
    }
    return self;
}


- (BOOL) ticsIn
{
    return s_tics_in;
}



- setTicsCoord:(int)coord isOn:(BOOL)isOn
{
    if (s_ticsCoord[coord] != isOn) {
	s_ticsCoord[coord] = isOn;
	[self reportSettingsChange:self];
    }
    return self;
}


- (BOOL) ticsCoord:(int)coord
{
    return s_ticsCoord[coord];
}



- setTicTypeCoord:(int)coord to:(int)anInt
{
    if (s_ticTypeCoord[coord] != anInt) {
	s_ticTypeCoord[coord] = anInt;
	[self reportSettingsChange:self];
    }
    return self;
}



- (int)ticTypeCoord:(int)coord
{
    return s_ticTypeCoord[coord];
}



- setTicStartCoord:(int)coord to:(double)aDouble
{
    if (s_ticSeriesCoord[coord].start != aDouble) {
	s_ticSeriesCoord[coord].start = aDouble;
	[self reportSettingsChange:self];
    }
    return self;
}


- (double)ticStartCoord:(int)coord
{
    return s_ticSeriesCoord[coord].start;
}



- setTicEndCoord:(int)coord to:(double)aDouble
{
    if (s_ticSeriesCoord[coord].end != aDouble) {
	s_ticSeriesCoord[coord].end = aDouble;
	[self reportSettingsChange:self];
    }
    return self;
}


- (double)ticEndCoord:(int)coord
{
    return s_ticSeriesCoord[coord].end;
}



- setTicIncrementCoord:(int)coord to:(double)aDouble
{
    if (s_ticSeriesCoord[coord].incr != aDouble) {
	s_ticSeriesCoord[coord].incr = aDouble;
	[self reportSettingsChange:self];
    }
    return self;
}


- (double)ticIncrementCoord:(int)coord
{
    return s_ticSeriesCoord[coord].incr;
}



- (DoubleValueSortedList *)ticDefsCoord:(int)coord
{
    return ticDefs[coord];
}



// Shuts up compiler
- (const char *) rcsid
{
    return RCSId;
}

@end
